﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Provider;
using Android.Util;
using Android.Widget;
using Java.Net;
using Path = System.IO.Path;
using Uri = Android.Net.Uri;

namespace GBU.Platform
{
    public static class BitmapHelper
    {
        private const string ImageThumbNameFormat = "{0}_s{1}";

        /// <summary>
        /// This method will recyle the memory help by a bitmap in an ImageView
        /// </summary>
        /// <param name="imageView">Image view.</param>
        public static void RecycleBitmap(this ImageView imageView)
        {
            if (imageView == null)
            {
                return;
            }

            Drawable toRecycle = imageView.Drawable;
            if (toRecycle != null)
            {
                ((BitmapDrawable)toRecycle).Bitmap.Recycle();
            }
        }

        /// <summary>
        /// 将系统相对Uri转换为图片文件的绝对路径
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="contentResolver">[一般情况下请用this.contentResolver]</param>
        /// <returns></returns>
        public static string ToImageFilePath(this Uri uri, ContentResolver contentResolver)
        {
            var filePath = string.Empty;
            string[] projects = { MediaStore.Images.ImageColumns.Data };

            var cusror = contentResolver.Query(uri, projects, null, null, null);
            cusror.MoveToFirst();

            var indexc = cusror.GetColumnIndex(projects[0]);
            filePath = cusror.GetString(indexc);
            cusror.Close();

            return filePath;
        }

        public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
        {
            // First we get the the dimensions of the file on disk
            BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
            BitmapFactory.DecodeFile(fileName, options);

            // Next we calculate the ratio that we need to resize the image by
            // in order to fit the requested dimensions.
            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;

            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }

            // Now we will load the image and have BitmapFactory resize it for us.
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);
            return resizedBitmap;
        }

        public static Bitmap LoadAndResizeBitmap(byte[] imgData, int width, int height)
        {
            // First we get the the dimensions of the file on disk
            BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
            BitmapFactory.DecodeByteArray(imgData,0,imgData.Length, options);

            // Next we calculate the ratio that we need to resize the image by
            // in order to fit the requested dimensions.
            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;

            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }

            // Now we will load the image and have BitmapFactory resize it for us.
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeByteArray(imgData,0,imgData.Length, options);
            return resizedBitmap;
        }

        public static Bitmap LoadAndResizeBitmap(this string fileName)
        {
            // First we get the the dimensions of the file on disk
            var inSampleSize = 1;
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            return BitmapFactory.DecodeFile(fileName, options);
        }

        public static byte[] LoadAndResizeBitmapBuffer(this string fileName, int width, int height)
        {
            byte[] buffer;
            using (var ms = new MemoryStream())
            {
                var img = fileName.LoadAndResizeBitmap(width, height);
                img.Compress(Bitmap.CompressFormat.Jpeg, 60, ms);
                buffer = new byte[ms.Length];
                ms.Read(buffer, 0, buffer.Length);
                img.Recycle();
            }

            return buffer;
        }

        public static string ResizeBitmapToFile(this string fileName)
        {
            // byte[] buffer;
            var fi = new FileInfo(fileName);
            var newfileName = global::System.IO.Path.Combine(fi.Directory.FullName, "fix_" + fi.Name);
            using (var fs = new FileStream(newfileName, FileMode.CreateNew))
            {
                var img = fileName.LoadAndResizeBitmap();

                img.Compress(Bitmap.CompressFormat.Jpeg, 60, fs);
                //buffer = new byte[ms.Length];
                // ms.Read(buffer, 0, buffer.Length);
                fs.Flush(true);
                img.Recycle();
            }
            return newfileName;
        }


        public static byte[] LoadResizeBitMapBuffer(this string fileName)
        {
            var newfile = fileName.ResizeBitmapToFile();
            byte[] buffer;
            using (FileStream fs = new FileStream(newfile, FileMode.Open))
            {
                buffer = new byte[fs.Length];
                fs.Read(buffer, 0, buffer.Length);
            }
            return buffer;
        }


        /// <summary>
        /// 读取url图片
        /// </summary>
        /// <param name="url">图片url</param>
        /// <param name="isThumb">是否缩略图</param>
        /// <returns></returns>
        public static Bitmap LoadBitmapFromUrl(string url, bool isThumb)
        {
            var fileUrl = url;
            if (isThumb)
            {
                fileUrl = FormatThumbUrl(url);
            }
            var imgUrl = new URL(fileUrl);

            return BitmapFactory.DecodeStream(imgUrl.OpenStream());
        }

        public static void LoadBitmapFromUrl(string url, bool isThumb, Action<FileDownloadState> downloadingCalback)
        {
            var fileUrl = url;
            if (isThumb)
            {
                fileUrl = FormatThumbUrl(url);
            }
            var imgUrl = new URL(fileUrl);

            Task.Factory.StartNew(() => DownloadBitmapFromUrlAsync(imgUrl, downloadingCalback));
        }

        public static void LoadBitmapFileFromUrl(string url, bool isThumb, Action<FileDownloadState> downloadingCalback)
        {
            var fileUrl = url;
            if (isThumb)
            {
                fileUrl = FormatThumbUrl(url);
            }
            var imgUrl = new URL(fileUrl);

            Task.Factory.StartNew(() => DownloadFileFromUrlAsync(imgUrl, downloadingCalback));
        }

        private static void DownloadBitmapFromUrlAsync(URL fileUrl, Action<FileDownloadState> downloadingCalback)
        {
            try
            {
                var conn = fileUrl.OpenConnection();
                conn.Connect();
                var inputStream = conn.InputStream;
                var fileSize = conn.ContentLength;
                var downloadSize = 0;
                if (fileSize < 1 || inputStream == null)
                {
                    if (downloadingCalback != null)
                    {
                        downloadingCalback(new FileDownloadState()
                        {
                            FileLength = 0,
                            DownloadLength = 0,
                            IsCompleted = false,
                            IsFault = true,
                            Msg = "Downloading content is null.",
                            Bitmap = null
                        }); //0, 0, false, true, "Content null", null);
                    }
                }
                else
                {
                    downloadingCalback(new FileDownloadState()
                    {
                        FileLength = fileSize,
                        DownloadLength = downloadSize,
                        IsCompleted = false,
                        IsFault = false,
                        Bitmap = null,
                        Msg = string.Empty
                    });

                    byte[] buffer = new byte[1024];

                    List<byte> fileContent = new List<byte>();
                    int readcount = -1;
                    while ((readcount = inputStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        fileContent.AddRange(buffer.Take(readcount));
                        downloadSize += readcount;

                        downloadingCalback(new FileDownloadState()
                        {
                            FileLength = fileSize,
                            DownloadLength = downloadSize,
                            IsCompleted = false,
                            IsFault = false,
                            Bitmap = null,
                            Msg = string.Empty
                        });
                    }

                    var bitmap = BitmapFactory.DecodeByteArray(fileContent.ToArray(), 0, fileContent.Count);

                    downloadingCalback(new FileDownloadState()
                    {
                        FileLength = fileSize,
                        DownloadLength = downloadSize,
                        IsCompleted = true,
                        IsFault = false,
                        Bitmap = bitmap,
                        Msg = string.Empty
                    });

                }
            }
            catch (Exception ex)
            {
                downloadingCalback(new FileDownloadState()
                {
                    FileLength = 0,
                    DownloadLength = 0,
                    IsCompleted = false,
                    IsFault = true,
                    Bitmap = null,
                    Msg = ex.Message
                });
            }
        }

        private static void DownloadFileFromUrlAsync(URL fileUrl, Action<FileDownloadState> downloadingCalback)
        {
            try
            {
                var conn = fileUrl.OpenConnection();
                conn.Connect();
                var inputStream = conn.InputStream;
                var fileSize = conn.ContentLength;
                var fileName = fileUrl.File.Substring(fileUrl.File.LastIndexOf("/") + 1);
                var fileNamePath = Path.Combine(DeviceHelper.GetCreatePicDirectory().Path, fileName);
                Log.Debug("bitmaphelper:", fileNamePath);
                var fi = new FileInfo(fileNamePath);
                if (fi.Exists)
                {
                    Log.Debug("BitMapHelper:", fileNamePath);
                    downloadingCalback(new FileDownloadState()
                    {
                        FileLength = (int)fi.Length,
                        DownloadLength = 0,
                        FilePath = fileNamePath,
                        IsCompleted = true,
                        IsFault = false,
                        Msg = string.Empty,
                        Bitmap = null
                    });
                    return;
                }

                var downloadSize = 0;
                if (fileSize < 1 || inputStream == null)
                {
                    if (downloadingCalback != null)
                    {
                        downloadingCalback(new FileDownloadState() { FileLength = 0, DownloadLength = 0, IsCompleted = false, IsFault = true, Msg = "Downloading content is null.", Bitmap = null });//0, 0, false, true, "Content null", null);
                    }
                }
                else
                {
                    downloadingCalback(new FileDownloadState()
                    {
                        FileLength = fileSize,
                        DownloadLength = downloadSize,
                        IsCompleted = false,
                        IsFault = false,
                        Bitmap = null,
                        Msg = string.Empty
                    });

                    using (FileStream fs = new FileStream(fileNamePath, FileMode.CreateNew,FileAccess.ReadWrite))
                    {
                        byte[] buffer = new byte[1024];
                        int readcount = -1;

                        while ((readcount = inputStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            fs.Write(buffer, 0, readcount);
                            downloadSize += readcount;
                            downloadingCalback(new FileDownloadState()
                            {
                                FileLength = fileSize,
                                DownloadLength = downloadSize,
                                IsCompleted = false,
                                IsFault = false,
                                Bitmap = null,
                                Msg = string.Empty
                            });
                        }
                        fs.Flush(true);
                    }
                    Log.Debug("BitmapHelper:", "file:" + fileNamePath);
                    FileInfo fi2 = new FileInfo(fileNamePath);
                    Log.Debug("BitmapHelper:", "file: Exist:" + fi.Exists);

                    downloadingCalback(new FileDownloadState()
                    {
                        FileLength = fileSize,
                        DownloadLength = downloadSize,
                        IsCompleted = true,
                        IsFault = false,
                        Bitmap = null,
                        FilePath = fileNamePath,
                        Msg = string.Empty
                    });

                }
            }
            catch (Exception ex)
            {
                downloadingCalback(new FileDownloadState()
                {
                    FileLength = 0,
                    DownloadLength = 0,
                    IsCompleted = false,
                    IsFault = true,
                    Bitmap = null,
                    FilePath = string.Empty,
                    Msg = ex.Message
                });
            }
        }

        private static string FormatThumbUrl(string source)
        {
            var index = source.LastIndexOf(".", StringComparison.Ordinal);
            return string.Format(ImageThumbNameFormat, source.Substring(0, index), source.Substring(index));
        }

        /// <summary>
        /// ImageView扩展方法
        /// </summary>
        /// <param name="imgView"></param>
        /// <param name="url"></param>
        /// <param name="isThumb"></param>
        public static void LoadFromUrl(this ImageView imgView, string url, bool isThumb=false)
        {
            BitmapHelper.LoadBitmapFromUrl(url, isThumb, (ret) =>
            {
                if (ret.IsCompleted)
                {
                    ((Activity)imgView.Context).RunOnUiThread(() =>
                    {
                        var filePath = ret.FilePath;
                        imgView.SetImageBitmap(ret.Bitmap);

                    });
                }
            });
        }

        /// <summary>
        /// ImageView扩展方法
        /// </summary>
        /// <param name="imgView"></param>
        /// <param name="url"></param>
        /// <param name="isThumb"></param>
        public static void LoadFromFile(this ImageView imgView, string filePath)
        {
            //BitmapHelper.LoadBitmapFromUrl(url, isThumb, (ret) =>
            //{
            //    if (ret.IsCompleted)
            //    {
            //        ((Activity)imgView.Context).RunOnUiThread(() =>
            //        {
            //            var filePath = ret.FilePath;
            //            imgView.SetImageBitmap(ret.Bitmap);

            //        });
            //    }
            //});

            
            //filePath.LoadBitMapAsync(imgView.Width, imgView.Height).ContinueWith((t) => imgView.SetImageBitmap(t.Result));
            
            
            imgView.SetImageBitmap(filePath.LoadBitMap(imgView.Width,imgView.Height));
        }


        public static Bitmap LoadBitMap(this string file, int w, int h)
        {
            return LoadAndResizeBitmap(file, w, h);
        }
    }

    public class FileDownloadState
    {
        public int FileLength { get; set; }
        public int DownloadLength { get; set; }
        public bool IsCompleted { get; set; }
        public bool IsFault { get; set; }
        public string Msg { get; set; }
        public Bitmap Bitmap { get; set; }
        public string FilePath { get; set; }
    }
}
